package com.jiangdg.usbcamera.usbcamera;

import android.app.Activity;
import android.content.Context;
import android.hardware.usb.UsbDevice;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.view.Surface;
import android.widget.Toast;

import com.jiangdg.usbcamera.UVCCameraHelper;
import com.jiangdg.usbcamera.application.MyApplication;
import com.jiangdg.usbcamera.utils.FileUtils;
import com.jiangdg.usbcamera.view.USBCameraActivity;
import com.serenegiant.usb.CameraDialog;
import com.serenegiant.usb.Size;
import com.serenegiant.usb.USBMonitor;
import com.serenegiant.usb.common.AbstractUVCCameraHandler;
import com.serenegiant.usb.encoder.RecordParams;
import com.serenegiant.usb.widget.CameraViewInterface;
import java.util.ArrayList;
import java.util.List;

public class USBCameraManager implements CameraDialog.CameraDialogParent{

    /**
     * 打印日志
     */
    private static String TAG  =  "[USBCameraManager]->";
    private boolean isSupportToast = true;

    /**
     * 界面回调
     *
     */
    private CameraViewInterface mUVCCameraView ;
    /**
     * 摄像头操作帮助类
     *
     */
    private UVCCameraHelper mCameraHelper ;
    /**
     * 记录权限请求
     *
     */
    private boolean isRequestPermission;
    /**
     * 记录预览状态
     *
     */
    private boolean isPreview;

    /**
     * 回调
     */
    private IUSBCameraCallBack cameraCallBack ;


    private Context context ;

    private static USBCameraManager manager ;

    public static USBCameraManager getInstance(){
        if (null == manager){
            synchronized (USBCameraManager.class){
                if (null==manager){
                    manager = new USBCameraManager();
                }
            }
        }
        return manager;
    }


    /**
     * 初始化
     *
     */
    public void init(Activity activity, CameraViewInterface mTextureView, IUSBCameraCallBack cameraCallBack){
        this.context=activity;
        this.cameraCallBack = cameraCallBack;
        mUVCCameraView = (CameraViewInterface) mTextureView;
        mUVCCameraView.setCallback(callback);

        mCameraHelper = UVCCameraHelper.getInstance();

        mCameraHelper.setDefaultFrameFormat(UVCCameraHelper.FRAME_FORMAT_MJPEG);
        mCameraHelper.setDefaultPreviewSize(640,480);
        mCameraHelper.setOnPreviewFrameListener(onPreViewResultListener);
        mCameraHelper.initUSBMonitor(activity, mUVCCameraView, listener);
    }



    /**
     * 注册usb监听
     *
     *
     * 在onStart()中调用
     */
    public void register(){
        if (mCameraHelper != null) {
            mCameraHelper.registerUSB();
        }
    }


    /**
     * 取消监听
     *
     * 在 onStop()中调用
     */
    public void unregister(){
        if (mCameraHelper != null) {
            mCameraHelper.unregisterUSB();
        }
    }




    private AbstractUVCCameraHandler.OnPreViewResultListener onPreViewResultListener = new AbstractUVCCameraHandler.OnPreViewResultListener(){

        @Override
        public void onPreviewResult(byte[] data) {
            showLog("[onPreviewResult]->"+data.length);
        }
    };


    /**
     * 相机连接的过程
     */
    private UVCCameraHelper.OnMyDevConnectListener listener = new UVCCameraHelper.OnMyDevConnectListener() {

        @Override
        public void onAttachDev(UsbDevice device) {
            // request open permission
            showLog("[onAttachDev] - > request open permission");
            if (!isRequestPermission) {
                isRequestPermission = true;
                if (mCameraHelper != null) {
                    mCameraHelper.requestPermission(0);
                }
            }
        }


        @Override
        public void onDettachDev(UsbDevice device) {
            showLog(String.format("[onDettachDev] - > %s camera is closed",device.getDeviceName()));
            if (isRequestPermission && mCameraHelper!=null) {
                isRequestPermission = false;
                mCameraHelper.closeCamera();
            }
        }


        @Override
        public void onConnectDev(UsbDevice device, boolean isConnected) {
            if (!isConnected) {
                showLog("[onConnectDev]-> fail to connect,please check resolution params");
                isPreview = false;
            } else {
                isPreview = true;
                showLog("[onConnectDev]-> connecting");
                // need to wait UVCCamera initialize over
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(2500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        Looper.prepare();
                        if(mCameraHelper != null && mCameraHelper.isCameraOpened()) {
                            if (cameraCallBack!=null){
                                cameraCallBack .onBrightness(mCameraHelper.getModelValue(UVCCameraHelper.MODE_BRIGHTNESS));
                                cameraCallBack .onContrast(mCameraHelper.getModelValue(UVCCameraHelper.MODE_CONTRAST));
                            }
                        }
                        Looper.loop();
                    }
                }).start();
            }
        }


        @Override
        public void onDisConnectDev(UsbDevice device) {
            showLog("[onDisConnectDev]->disconnecting");
        }
    };




    private CameraViewInterface.Callback callback = new CameraViewInterface.Callback(){

        @Override
        public void onSurfaceCreated(CameraViewInterface view, Surface surface) {
            if (!isPreview && mCameraHelper.isCameraOpened()) {
                mCameraHelper.startPreview(mUVCCameraView);
                isPreview = true;
            }
        }

        @Override
        public void onSurfaceChanged(CameraViewInterface view, Surface surface, int width, int height) {

        }

        @Override
        public void onSurfaceDestroy(CameraViewInterface view, Surface surface) {
            if (isPreview && mCameraHelper.isCameraOpened()) {
                mCameraHelper.stopPreview();
                isPreview = false;
            }
        }
    };


    /**
     * 相机是否已经开启
     *
     * @return
     */
    public boolean isCameraOpened(){
        return (mCameraHelper != null && mCameraHelper.isCameraOpened());
    }


    /**
     * 展示log信息
     *
     * @param msg
     */
    public void showLog(String msg){
        runMainUIThread(new Runnable() {
            @Override
            public void run() {
                Log.v(TAG,msg);
                if (isSupportToast){
                    Toast.makeText(context,msg,Toast.LENGTH_LONG).show();
                }
            }
        });
    }



    /**
     * @param runnable
     */
    public void runMainUIThread(Runnable runnable){
        new Handler(context.getMainLooper()).post(runnable);
    }




    @Override
    public USBMonitor getUSBMonitor() {
        return mCameraHelper.getUSBMonitor();
    }


    @Override
    public void onDialogResult(boolean canceled) {
        if (canceled) {
            showLog("[onDialogResult]->取消操作");
        }
    }


    /**
     * 拍照
     */
    public void takePicture(){
        if (!isCameraOpened()) {
            showLog("[takePicture]->sorry,camera open failed");
            return;
        }

        String picPath = UVCCameraHelper.ROOT_PATH
                + MyApplication.DIRECTORY_NAME
                +"/images/"
                + System.currentTimeMillis()
                + UVCCameraHelper.SUFFIX_JPEG;

        mCameraHelper.capturePicture(picPath, new AbstractUVCCameraHandler.OnCaptureListener() {
            @Override
            public void onCaptureResult(String path) {
                if(TextUtils.isEmpty(path)) {
                    showLog("拍照失败！");
                    return;
                }
                showLog(String.format( "[takePicture]save path:%s",path));
            }
        });
    }



    /**
     * 拍照
     */
    public void startRecord(){
        if (!isCameraOpened()){
            showLog("[startRecord]->sorry,camera open failed");
            return;
        }

        if (!mCameraHelper.isPushing()) {
            String videoPath = UVCCameraHelper.ROOT_PATH
                    + MyApplication.DIRECTORY_NAME +"/videos/"
                    + System.currentTimeMillis()
                    + UVCCameraHelper.SUFFIX_MP4;
//                    FileUtils.createfile(FileUtils.ROOT_PATH + "test666.h264");
            // if you want to record,please create RecordParams like this
            RecordParams params = new RecordParams();
            /*视频路径*/
            params.setRecordPath(videoPath);
            // auto divide saved,default 0 means not divided
            // 自动分割保存，默认0表示不分割
            params.setRecordDuration(0);
            // is close voice  控制声音是否开还是关
            params.setVoiceClose(false);
            // overlay only support armeabi-v7a & arm64-v8a
            params.setSupportOverlay(true);

            mCameraHelper.startPusher(params, new AbstractUVCCameraHandler.OnEncodeResultListener() {
                @Override
                public void onEncodeResult(byte[] data, int offset, int length, long timestamp, int type) {
                    // type = 1,h264 video stream
                    if (type == 1) {
                        FileUtils.putFileStream(data, offset, length);
                    }
                    // type = 0,aac audio stream
                    if(type == 0) {

                    }
                    showLog("[onEncodeResult] -> (type = 1,h264 video stream type = 0,aac audio stream) = "+type+",data="+data.length);
                }

                @Override
                public void onRecordResult(String videoPath) {
                    if(TextUtils.isEmpty(videoPath)) {
                        showLog("[onRecordResult] ->视频录制失败了");
                        return;
                    }
                    showLog(String.format("[onRecordResult] save videoPath:%s",videoPath));
                }
            });


            // if you only want to push stream,please call like this
            // mCameraHelper.startPusher(listener);
            showLog("start record...");
        }
    }






    /**
     * 停止录制
     */
    public void stopRecord(){
        if (!isCameraOpened()){
            showLog("[startRecord]->sorry,camera open failed");
            return;
        }
        FileUtils.releaseFile();
        mCameraHelper.stopPusher();
        showLog("[stopRecord]-> stop record...");
    }




    /**
     * 对焦
     */
    public void startCameraFocusable(){
        if (!isCameraOpened()) {
            showLog("[startCameraFocusable]->sorry,camera open failed");
            return;
        }
        mCameraHelper.startCameraFoucs();
    }





    /**
     * 更新分辨率
     *
     * @param width
     * @param height
     */
    public void updateResolution(int width, int height){
        if (isCameraOpened()){
            mCameraHelper.updateResolution(width,height);
        }else {
            showLog("[startCameraFocusable]->sorry,camera open failed");
        }
    }





    /**
     * 展示分辨率
     *
     */
    public void showResolutionList(){
        if (isCameraOpened()){
            ResolutionListDialog.showResolutionListDialog(context,getResolutionList());
        }else {
            showLog("[showResolutionList] -> sorry,camera open failed");
        }
    }



    /**
     * 获取支持的分辨率
     *
     * @return
     */
    public List<String> getResolutionList() {
        if (mCameraHelper!=null){
            List<Size> list = mCameraHelper.getSupportedPreviewSizes();
            List<String> resolutions = null;
            if (list != null && list.size() != 0) {
                resolutions = new ArrayList<>();
                for (Size size : list) {
                    if (size != null) {
                        resolutions.add(size.width + "x" + size.height);
                    }
                }
            }
            return resolutions;
        }
        showLog("[getResolutionList] -> mCameraHelper is null");
       return null ;
    }



    /**
     * 释放
     *
     * 资源
     */
    public void release(){
        FileUtils.releaseFile();
        // step.4 release uvc camera resources
        if (mCameraHelper != null) {
            mCameraHelper.release();
        }
        showLog("[release] -> 释放usb相机资源");
    }

}
